/**
 * 
 */
package org.yelongframework.model.support.mybatis.sql.fragment.attribute;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.JdbcType;
import org.yelongframework.core.util.map.AttrMap;
import org.yelongframework.model.support.mybatis.mapping.parameter.DefaultMappingParameterTypeDeducer;
import org.yelongframework.model.support.mybatis.mapping.parameter.MappingParameterTypeDeducer;
import org.yelongframework.model.support.mybatis.sql.MybatisBoundSql;
import org.yelongframework.model.support.mybatis.sql.MybatisParamMap;
import org.yelongframework.sql.fragment.AbstractSqlFragment;

/**
 * mybatis属性SQL片段抽象实现
 * 
 * @since 1.0.0
 */
public abstract class AbstractMybatisAttributeSqlFragment extends AbstractSqlFragment
		implements MybatisAttributeSqlFragment {

	/** 映射此参数类型推断器 */
	private MappingParameterTypeDeducer mappingParameterTypeDeducer = new DefaultMappingParameterTypeDeducer();

	/**
	 * mybatis映射文件中取条件的占位符 。${attribute}
	 */
	public static final String ATTRIBUTE_FLAG = "attribute";

	private final Map<String, MybatisAttributeSqlFragmentAttribute> attrMap = new LinkedHashMap<>();

	private String mybatisParamAlias;

	@Override
	public void addAttr(String attrName, Object value) {
		JdbcType jdbcType = mappingParameterTypeDeducer.deduce(value);
		addAttr(attrName, value, null != jdbcType ? jdbcType.name() : null);
	}

	@Override
	public void addAttrs(Map<String, Object> attrs) {
		attrs.forEach((k, v) -> {
			addAttr(k, v);
		});
	}

	@Override
	public boolean removeAttr(String attrName) {
		return attrMap.remove(attrName) != null;
	}

	@Override
	public boolean containsAttr(String attrName) {
		return attrMap.containsKey(attrName);
	}

	@Override
	public Object getAttrValue(String attrName) {
		MybatisAttributeSqlFragmentAttribute attribute = attrMap.get(attrName);
		return attribute == null ? null : attribute.getValue();
	}

	@Override
	public boolean isEmptyAttr() {
		return attrMap.isEmpty();
	}

	@Override
	public AttrMap getAttrMap() {
		AttrMap attrMap = new AttrMap();
		this.attrMap.values().stream().forEach(x -> {
			attrMap.put(x.getAttrName(), x.getValue());
		});
		return attrMap;
	}

	@Override
	public String[] getMyBatisPlaceholderAll() {
		return ArrayUtils.toArray(ATTRIBUTE_FLAG);
	}

	@Override
	public Object getMyBatisPlaceholderValue(String placeholder) {
		if (ATTRIBUTE_FLAG.equalsIgnoreCase(placeholder)) {
			return getMybatisBoundSql().getMybatisSql();
		}
		return null;
	}

	@Override
	public void addAttr(String attrName, Object value, String jdbcType) {
		this.attrMap.put(attrName, new MybatisAttributeSqlFragmentAttribute(attrName, value, jdbcType));
	}

	@Override
	public Map<String, MybatisAttributeSqlFragmentAttribute> getMybatisAttrMap() {
		return attrMap;
	}

	@Override
	public MybatisBoundSql getMybatisBoundSql() {
		MybatisParamMap mybatisParamMap = new MybatisParamMap("MYBATISPARAM");
		Collection<MybatisAttributeSqlFragmentAttribute> attrs = getMybatisAttrMap().values();
		for (MybatisAttributeSqlFragmentAttribute mybatisAttribute : attrs) {
			mybatisParamMap.addParamMap(mybatisAttribute.getValue(), mybatisAttribute.getJdbcType());
		}
		if (StringUtils.isNotEmpty(getParamAlias())) {
			mybatisParamMap.setParamAlias(getParamAlias());
		}
		// 修改生成的占位符？为mybatis占位符
		StringBuilder sqlFragment = new StringBuilder(getSqlBound(null).getSql());
		Set<String> mybatisParamPlaceholderSet = mybatisParamMap.getPlaceholderParamMap().keySet();
		for (String paramPlaceholder : mybatisParamPlaceholderSet) {
			int index = sqlFragment.indexOf("?");
			sqlFragment.replace(index, index + 1, paramPlaceholder);
		}
		String sql = sqlFragment.toString();
		return new MybatisBoundSql(sql, mybatisParamMap);
	}

	@Override
	public void setParamAlias(String paramAlias) {
		this.mybatisParamAlias = paramAlias;
	}

	@Override
	public String getParamAlias() {
		return mybatisParamAlias;
	}

}
